home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 1 / QRZ Ham Radio Callsign Database - December 1993.iso / ucsd / packet / tcpip / sys5 / iscwmpst.z / iscwmpst / tcp / src / rip.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-22  |  16.0 KB  |  679 lines

  1. /* @(#) $Header: rip.c,v 1.4 91/05/21 19:09:14 deyke Exp $ */
  2.  
  3. /* This file contains code to implement the Routing Information Protocol (RIP)
  4.  * and is derived from 4.2BSD code. Mike Karels of Berkeley has stated on
  5.  * TCP-IP that the code may be freely used as long as UC Berkeley is
  6.  * credited. (Well, here's some credit :-). AGB 4-28-88
  7.  
  8.  * Further documentation on the RIP protocol is now available in Charles
  9.  * Hedrick's draft RFC, as yet unnumbered. AGB 5-6-88
  10.  *
  11.  * The RIP RFC has now been issued as RFC1058. AGB 7-23-88
  12.  *
  13.  * Code gutted and substantially rewritten. KA9Q 9/89
  14.  */
  15. #include "global.h"
  16. #include "mbuf.h"
  17. #include "netuser.h"
  18. #include "udp.h"
  19. #include "timer.h"
  20. #include "iface.h"
  21. #include "ip.h"
  22. #include "internet.h"
  23. #include "rip.h"
  24. #include "arp.h"
  25.  
  26. struct rip_stat Rip_stat;
  27. int16 Rip_trace;
  28. int Rip_merge;
  29. struct rip_list *Rip_list;
  30. struct udp_cb *Rip_cb;
  31.  
  32. struct rip_refuse *Rip_refuse;
  33.  
  34. static void rip_rx __ARGS((struct iface *iface,struct udp_cb *sock,int cnt));
  35. static void proc_rip __ARGS((struct iface *iface,int32 gateway,
  36.     struct rip_route *ep));
  37. static char *putheader __ARGS((char *cp,int command,int version));
  38. static char *putentry __ARGS((char *cp,int fam,int32 target,int32 metric));
  39. static void rip_shout __ARGS((void *p));
  40. static void send_routes __ARGS((int32 dest,int port,int split,int trig));
  41.  
  42. /* Send RIP CMD_RESPONSE packet(s) to the specified rip_list entry */
  43. static void
  44. rip_shout(p)
  45. void *p;
  46. {
  47.     register struct rip_list *rl;
  48.  
  49.     rl = (struct rip_list *)p;
  50.     stop_timer(&rl->rip_time);
  51.     send_routes(rl->dest,RIP_PORT,(rl->flags & RIP_SPLIT),0);
  52.     set_timer(&rl->rip_time,rl->interval*1000L);
  53.     start_timer(&rl->rip_time);
  54. }
  55.  
  56. /* Send the routing table. */
  57. static void
  58. send_routes(dest,port,split,trig)
  59. int32 dest;             /* IP destination address to send to */
  60. int16 port;
  61. int split;              /* Do split horizon? */
  62. int trig;               /* Send only triggered updates? */
  63. {
  64.     char *cp;
  65.     int i,bits,numroutes,maxroutes;
  66.     int16 pktsize;
  67.     struct mbuf *bp;
  68.     struct route *rp;
  69.     struct socket lsock,fsock;
  70.     struct iface *iface;
  71.  
  72.     if((rp = rt_lookup(dest)) == NULLROUTE)
  73.         return; /* No route exists, can't do it */
  74.     iface = rp->iface;
  75.  
  76.     /* Compute maximum packet size and number of routes we can send */
  77.     pktsize = ip_mtu(dest) - IPLEN;
  78.     pktsize = min(pktsize,MAXRIPPACKET);
  79.     maxroutes = (pktsize - RIPHEADER) / RIPROUTE;
  80.  
  81.     lsock.address = INADDR_ANY;
  82.     lsock.port = RIP_PORT;
  83.     fsock.address = dest;
  84.     fsock.port = port;
  85.  
  86.     /* Allocate space for a full size RIP packet and generate header */
  87.     if((bp = alloc_mbuf(pktsize)) == NULLBUF)
  88.         return;
  89.     numroutes = 0;
  90.     cp = putheader(bp->data,RIPCMD_RESPONSE,RIPVERSION);
  91.  
  92.     /* Emit default route, if appropriate */
  93.     if(R_default.iface != NULLIF && !(R_default.flags & RTPRIVATE)
  94.      && (!trig || (R_default.flags & RTTRIG))){
  95.         if(!split || iface != R_default.iface){
  96.             cp = putentry(cp,RIP_IPFAM,0,R_default.metric);
  97.             numroutes++;
  98.         } else if(trig){
  99.             cp = putentry(cp,RIP_IPFAM,0,RIP_INFINITY);
  100.             numroutes++;
  101.         }
  102.     }
  103.     for(bits=0;bits<32;bits++){
  104.         for(i=0;i<HASHMOD;i++){
  105.             for(rp = Routes[bits][i];rp != NULLROUTE;rp=rp->next){
  106.                 if((rp->flags & RTPRIVATE)
  107.                  || (trig && !(rp->flags & RTTRIG)))
  108.                     continue;
  109.  
  110.                 if(numroutes >= maxroutes){
  111.                     /* Packet full, flush and make another */
  112.                     bp->cnt = RIPHEADER + numroutes * RIPROUTE;
  113.                     send_udp(&lsock,&fsock,0,0,bp,bp->cnt,0,0);
  114.                     Rip_stat.output++;
  115.                     if((bp = alloc_mbuf(pktsize)) == NULLBUF)
  116.                         return;
  117.                     numroutes = 0;
  118.                     cp = putheader(bp->data,RIPCMD_RESPONSE,RIPVERSION);
  119.                 }
  120.                 if(!split || iface != rp->iface){
  121.                     cp = putentry(cp,RIP_IPFAM,rp->target,rp->metric);
  122.                     numroutes++;
  123.                 } else if(trig){
  124.                     cp = putentry(cp,RIP_IPFAM,rp->target,RIP_INFINITY);
  125.                     numroutes++;
  126.                 }
  127.             }
  128.         }
  129.     }
  130.     if(numroutes != 0){
  131.         bp->cnt = RIPHEADER + numroutes * RIPROUTE;
  132.         send_udp(&lsock,&fsock,0,0,bp,bp->cnt,0,0);
  133.         Rip_stat.output++;
  134.     } else {
  135.         free_p(bp);
  136.     }
  137. }
  138. /* Add an entry to the rip broadcast list */
  139. int
  140. rip_add(dest,interval,flags)
  141. int32 dest;
  142. int32 interval;
  143. char flags;
  144. {
  145.     register struct rip_list *rl;
  146.     struct route *rp;
  147.  
  148.     for(rl = Rip_list; rl != NULLRL; rl = rl->next)
  149.         if(rl->dest == dest)
  150.             return 0;
  151.  
  152.     if((rp = rt_lookup(dest)) == NULLROUTE){
  153.         tprintf("%s is unreachable\n",inet_ntoa(dest));
  154.         return 1;
  155.     }
  156.     /* get a chunk of memory for the rip interface descriptor */
  157.     rl = (struct rip_list *)callocw(1,sizeof(struct rip_list));
  158.  
  159.     /* tack this record on as the first in the list */
  160.     rl->next = Rip_list;
  161.     if(rl->next != NULLRL)
  162.         rl->next->prev = rl;
  163.     Rip_list = rl;
  164.  
  165.     rl->dest = dest;
  166.  
  167.     /* and the interface ptr, tick interval and flags */
  168.     rl->iface = rp->iface;
  169.     rl->interval = interval;
  170.     rl->flags = flags;
  171.  
  172.     /* and set up the timer stuff */
  173.     set_timer(&rl->rip_time,interval*1000L);
  174.     rl->rip_time.func = rip_shout;
  175.     rl->rip_time.arg = rl;
  176.     start_timer(&rl->rip_time);
  177.     return 0;
  178. }
  179.  
  180. /* add a gateway to the rip_refuse list which allows us to ignore their
  181.  * advertisements
  182. */
  183. int
  184. riprefadd(gateway)
  185. int32 gateway;
  186. {
  187.     register struct rip_refuse *rl;
  188.  
  189.     for(rl = Rip_refuse; rl != NULLREF; rl = rl->next)
  190.         if(rl->target == gateway)
  191.             return 0;       /* Already in table */
  192.  
  193.     /* get a chunk of memory for the rip interface descriptor */
  194.     rl = (struct rip_refuse *)callocw(1,sizeof(struct rip_refuse));
  195.  
  196.     /* tack this record on as the first in the list */
  197.     rl->next = Rip_refuse;
  198.     if(rl->next != NULLREF)
  199.         rl->next->prev = rl;
  200.     Rip_refuse = rl;
  201.  
  202.     /* fill in the gateway to ignore */
  203.     rl->target = gateway;
  204.     return 0;
  205. }
  206.  
  207. /* drop a RIP target */
  208. int
  209. rip_drop(dest)
  210. int32   dest;
  211. {
  212.     register struct rip_list *rl;
  213.  
  214.     for(rl = Rip_list; rl != NULLRL; rl = rl->next)
  215.         if(rl->dest == dest)
  216.             break;
  217.  
  218.     /* leave if we didn't find it */
  219.     if(rl == NULLRL)
  220.         return 0;
  221.  
  222.     /* stop the timer */
  223.     stop_timer(&rl->rip_time);
  224.  
  225.     /* Unlink from list */
  226.     if(rl->next != NULLRL)
  227.         rl->next->prev = rl->prev;
  228.     if(rl->prev != NULLRL)
  229.         rl->prev->next = rl->next;
  230.     else
  231.         Rip_list = rl->next;
  232.  
  233.     /* and deallocate the descriptor memory */
  234.     free((char *)rl);
  235.     return 0;
  236. }
  237.  
  238. /* drop a RIP-refuse target from the rip_refuse list */
  239. int
  240. riprefdrop(gateway)
  241. int32 gateway;
  242. {
  243.     register struct rip_refuse *rl;
  244.  
  245.     for(rl = Rip_refuse; rl != NULLREF; rl = rl->next)
  246.         if(rl->target == gateway)
  247.             break;
  248.  
  249.     /* leave if we didn't find it */
  250.     if(rl == NULLREF)
  251.         return 0;
  252.  
  253.     /* Unlink from list */
  254.     if(rl->next != NULLREF)
  255.         rl->next->prev = rl->prev;
  256.     if(rl->prev != NULLREF)
  257.         rl->prev->next = rl->next;
  258.     else
  259.         Rip_refuse = rl->next;
  260.  
  261.     /* and deallocate the structure memory */
  262.     free((char *)rl);
  263.     return 0;
  264. }
  265.  
  266. /* function to output a RIP CMD_RESPONSE packet for the rip_trigger list */
  267. void
  268. rip_trigger()
  269. {
  270.     register struct rip_list *rl;
  271.     int bits,i;
  272.     struct route *rp;
  273.  
  274.     for(rl=Rip_list;rl != NULLRL;rl = rl->next){
  275.         send_routes(rl->dest,RIP_PORT,(rl->flags & RIP_SPLIT),1);
  276.     }
  277.     /* Clear the trigger list */
  278.     R_default.flags &= ~RTTRIG;
  279.     for(bits=0;bits<32;bits++){
  280.         for(i=0;i<HASHMOD;i++){
  281.             for(rp = Routes[bits][i];rp != NULLROUTE;rp = rp->next){
  282.                 rp->flags &= ~RTTRIG;
  283.             }
  284.         }
  285.     }
  286. }
  287.  
  288. /* Start RIP agent listening at local RIP UDP port */
  289. int
  290. rip_init()
  291. {
  292.     struct socket lsock;
  293.  
  294.     lsock.address = INADDR_ANY;
  295.     lsock.port = RIP_PORT;
  296.  
  297.     if(Rip_cb == NULLUDP)
  298.         Rip_cb = open_udp(&lsock,rip_rx);
  299.  
  300.     return 0;
  301. }
  302.  
  303. /* Process RIP input received from 'interface'. */
  304. static void
  305. rip_rx(iface,sock,cnt)
  306. struct iface *iface;
  307. struct udp_cb *sock;
  308. int cnt;
  309. {
  310.     struct mbuf *bp;
  311.     struct socket fsock;
  312.     int cmd;
  313.     register struct rip_refuse *rfl;
  314.     struct rip_route entry;
  315.     struct route *rp;
  316.  
  317.     /* receive the RIP packet */
  318.     recv_udp(sock,&fsock,&bp);
  319.  
  320.     /* increment the rcvd cnt */
  321.     Rip_stat.rcvd++;
  322.  
  323.     /* check the gateway of this packet against the rip_refuse list and
  324.      * discard it if a match is found
  325.      */
  326.     for(rfl=Rip_refuse;rfl != NULLREF;rfl = rfl->next){
  327.         if(fsock.address == rfl->target){
  328.             Rip_stat.refusals++;
  329.             if(Rip_trace > 1)
  330.                 printf("RIP refused from %s\n",
  331.                  inet_ntoa(fsock.address));
  332.             free_p(bp);
  333.             return;
  334.          }
  335.     }
  336.     cmd = PULLCHAR(&bp);
  337.     /* Check the version of the frame */
  338.     if(PULLCHAR(&bp) != RIPVERSION){
  339.         free_p(bp);
  340.         Rip_stat.version++;
  341.         return;
  342.     }
  343.     switch(cmd){
  344.     case RIPCMD_RESPONSE:
  345.         if(Rip_trace > 1)
  346.             printf("RIPCMD_RESPONSE from %s \n",inet_ntoa(fsock.address));
  347.  
  348.         Rip_stat.response++;
  349.         (void)pull16(&bp);      /* remove one word of padding */
  350.         while(len_p(bp) >= RIPROUTE){
  351.             pullentry(&entry,&bp);
  352.             proc_rip(iface,fsock.address,&entry);
  353.         }
  354.         /* If we can't reach the sender of this update, or if
  355.          * our existing route is not through the interface we
  356.          * got this update on, add him as a host specific entry
  357.          */
  358.         if((rp = rt_blookup(fsock.address,32)) != NULLROUTE){
  359.             /* Host-specific route already exists, refresh it */
  360.             start_timer(&rp->timer);
  361.         } else if((rp = rt_lookup(fsock.address)) == NULLROUTE
  362.          || rp->iface != iface){
  363.             entry.addr_fam = RIP_IPFAM;
  364.             entry.target = fsock.address;
  365.             entry.metric = 0; /* will get incremented to 1 */
  366.             proc_rip(iface,fsock.address,&entry);
  367.         }
  368.         if(Rip_merge)
  369.             rt_merge(Rip_trace);
  370.         rip_trigger();
  371.         break;
  372.     case RIPCMD_REQUEST:
  373.         if(Rip_trace > 1)
  374.             printf("RIPCMD_REQUEST\n");
  375.  
  376.         Rip_stat.request++;
  377.         /* For now, just send the whole table with split horizon
  378.          * enabled when the source port is RIP_PORT, and send
  379.          * the whole table with split horizon disable when another
  380.          * source port is used. This should be replaced with a more
  381.          * complete implementation that checks for non-global requests
  382.          */
  383.         if(fsock.port == RIP_PORT)
  384.             send_routes(fsock.address,fsock.port,1,0);
  385.         else
  386.             send_routes(fsock.address,fsock.port,0,0);
  387.         break;
  388.     default:
  389.         if(Rip_trace > 1)
  390.             printf("RIPCMD: Unknown Type\n");
  391.  
  392.         Rip_stat.unknown++;
  393.         break;
  394.     } /* switch */
  395.     free_p(bp);
  396. }
  397. /* Apply a set of heuristics for determining the number of significant bits
  398.  * (i.e., the address mask) in the target address. Needed since RIP doesn't
  399.  * include the address mask for each entry.
  400.  */
  401. int
  402. nbits(target)
  403. int32 target;
  404. {
  405.     int bits;
  406.  
  407.     if(target == 0)
  408.         return 0;       /* Special case: 0.0.0.0 is the default route */
  409.  
  410.     /* Check the host-part bytes of
  411.      * the address to check for byte-wide zeros
  412.      * which we'll consider to be subnet routes.
  413.      * e.g. 44.80.0.0 will be considered to be equal to 44.80/16
  414.      * whereas 44.80.1.0 will be considered to be 44.80.1/24
  415.      */
  416.     switch (hibyte(hiword(target)) >> 6) {
  417.     case 3: /* Class C address */
  418.         /*is it a host address ? i.e. are there any 1's in the
  419.          * host part ?
  420.          */
  421.         if(target & 0xff)
  422.             bits = 32;
  423.         else
  424.             bits = 24;
  425.         break;
  426.     case 2:  /* Class B address */
  427.         if(target & 0xff)
  428.             bits = 32;
  429.         else if(target & 0xff00)
  430.             bits = 24;
  431.         else
  432.             bits = 16;
  433.         break;
  434.     case 0:   /* Class A address */
  435.     case 1:
  436.         if(target & 0xff)
  437.             bits = 32;
  438.         else if(target & 0xff00)
  439.             bits = 24;
  440.         else if(target & 0xff0000)
  441.             bits = 16;
  442.         else
  443.             bits = 8;
  444.     }
  445.  
  446.     return bits;
  447. }
  448. /* Remove and process a RIP response entry from a packet */
  449. static void
  450. proc_rip(iface,gateway,ep)
  451. struct iface *iface;
  452. int32 gateway;
  453. register struct rip_route *ep;
  454. {
  455.     int32 interval;
  456.     unsigned int bits;
  457.     register struct route *rp;
  458.     struct rip_list *rl;
  459.     int add = 0;    /* action flags */
  460.     int drop = 0;
  461.     int trigger = 0;
  462.  
  463.     if(ep->addr_fam != RIP_IPFAM) {
  464.         /* Skip non-IP addresses */
  465.         if(Rip_trace > 1)
  466.             printf("RIP_rx: Not an IP RIP packet !\n");
  467.         Rip_stat.addr_family++;
  468.         return;
  469.     }
  470.     /* Guess at the mask, since it's not explicit */
  471.     bits = nbits(ep->target);
  472.  
  473.     /* Don't ever add a route to myself through somebody! */
  474.     if(bits == 32 && ismyaddr(ep->target) != NULLIF){
  475.         if(Rip_trace > 1){
  476.             printf("route to self: %s %ld\n",
  477.              inet_ntoa(ep->target),ep->metric);
  478.         }
  479.         return;
  480.     }
  481.     /* Update metric to reflect link cost */
  482.     ep->metric++;
  483.     ep->metric = min(ep->metric,RIP_INFINITY);
  484.  
  485.     /* Find existing entry, if any */
  486.     rp = rt_blookup(ep->target,bits);
  487.  
  488.     /* Don't touch private routes */
  489.     if(rp != NULLROUTE && (rp->flags & RTPRIVATE))
  490.         return;
  491.  
  492.     if(rp == NULLROUTE){
  493.         if(ep->metric < RIP_INFINITY){
  494.             /* New route; add it and trigger an update */
  495.             add++;
  496.             trigger++;
  497.         }
  498.     } else if(rp->metric == RIP_INFINITY){
  499.         /* Route is in hold-down; ignore this guy */
  500.         if(Rip_trace > 0){
  501.             printf("ignored (hold-down): %s %lu\n",
  502.              inet_ntoa(ep->target),ep->metric);
  503.         }
  504.     } else if(rp->gateway == gateway && rp->iface == iface){
  505.         /* This is the gateway for the entry we already have;
  506.          * restart the timer
  507.          */
  508.         start_timer(&rp->timer);
  509.         if(rp->metric != ep->metric){
  510.             /* Metric has changed. Update it and trigger an
  511.              * update. If route has become unavailable, start
  512.              * the hold-down timeout.
  513.              */
  514.             if(Rip_trace){
  515.                 printf("metric change: %s %lu -> %lu\n",
  516.                  inet_ntoa(ep->target),rp->metric,ep->metric);
  517.             }
  518.             if(ep->metric == RIP_INFINITY)
  519.                 rt_timeout(rp); /* Enter hold-down timeout */
  520.             else
  521.                 rp->metric = ep->metric;
  522.             trigger++;
  523.         }
  524.     } else {
  525.         /* Entry is from a different gateway than the current route */
  526.         if(ep->metric < rp->metric){
  527.             /* Switch to a new gateway */
  528.             if(Rip_trace > 0){
  529.                 printf("metric better: %s %lu\n",
  530.                  inet_ntoa(ep->target),ep->metric);
  531.             }
  532.             drop++;
  533.             add++;
  534.             trigger++;
  535.         } else {
  536.             /* Metric is no better, stay with current route */
  537.             if(Rip_trace > 1){
  538.                 printf("metric not better: %s %lu\n",
  539.                  inet_ntoa(ep->target),ep->metric);
  540.             }
  541.         }
  542.     }
  543.     if(drop){
  544.         /* Switching to a better gateway; delete old entry */
  545.         if(Rip_trace){
  546.             printf("route drop [%s]/%u",
  547.              inet_ntoa(ep->target),bits);
  548.             if(rp != NULLROUTE)
  549.                 printf(" %s %s %lu",rp->iface->name,
  550.                  inet_ntoa(rp->gateway),rp->metric);
  551.             printf("\n");
  552.         }
  553.         rt_drop(ep->target,bits);
  554.     }
  555.     if(add){
  556.         /* Add a new entry */
  557.         interval = RIP_TTL;
  558.         for(rl=Rip_list; rl != NULLRL; rl = rl->next){
  559.             if(rl->iface == iface){
  560.                 interval = rl->interval * 4;
  561.                 break;
  562.             }
  563.         }
  564.         if(Rip_trace > 0){
  565.             printf("route add [%s]/%u %s",inet_ntoa(ep->target),
  566.              bits,iface->name);
  567.             printf(" [%s] %u\n",inet_ntoa(gateway),
  568.              (int)ep->metric);
  569.         }
  570.         rp = rt_add(ep->target,(unsigned) bits,gateway,iface,
  571.          (int) ep->metric,interval,0);
  572.     }
  573.     /* If the route changed, mark it for a triggered update */
  574.     if(trigger){
  575.         rp->flags |= RTTRIG;
  576.     }
  577. }
  578. /* Send a RIP request packet to the specified destination */
  579. int
  580. ripreq(dest,replyport)
  581. int32 dest;
  582. int16 replyport;
  583. {
  584.     struct mbuf *bp;
  585.     struct socket lsock,fsock;
  586.     char *cp;
  587.  
  588.     lsock.address = INADDR_ANY;
  589.     lsock.port = replyport;
  590.  
  591.     /* if we were given a valid dest addr, ask it (the routers on that net)
  592.      * for a default gateway
  593.      */
  594.     if(dest == 0)
  595.         return 0;
  596.  
  597.     fsock.address = dest;
  598.     fsock.port = RIP_PORT;
  599.  
  600.     /* Send out one RIP Request packet as a broadcast to 'dest'  */
  601.     if((bp = alloc_mbuf(RIPHEADER + RIPROUTE)) == NULLBUF)
  602.         return -1;
  603.  
  604.     cp = putheader(bp->data,RIPCMD_REQUEST,RIPVERSION);
  605.     cp = putentry(cp,0,0L,RIP_INFINITY);
  606.     bp->cnt = RIPHEADER + RIPROUTE;
  607.     send_udp(&lsock, &fsock,0,0,bp,bp->cnt,0,0);
  608.     Rip_stat.output++;
  609.     return 0;
  610. }
  611. void
  612. pullentry(ep,bpp)
  613. register struct rip_route *ep;
  614. struct mbuf **bpp;
  615. {
  616.     ep->addr_fam = pull16(bpp);
  617.     (void)pull16(bpp);
  618.     ep->target = pull32(bpp);
  619.     (void)pull32(bpp);
  620.     (void)pull32(bpp);
  621.     ep->metric = pull32(bpp);
  622. }
  623.  
  624. /* Write the header of a RIP packet */
  625. static char *
  626. putheader(cp,command,version)
  627. register char *cp;
  628. char command;
  629. char version;
  630. {
  631.     *cp++ = command;
  632.     *cp++ = version;
  633.     return put16(cp,0);
  634. }
  635.  
  636. /* Write a single entry into a rip packet */
  637. static char *
  638. putentry(cp,fam,target,metric)
  639. register char *cp;
  640. int16 fam;
  641. int32 target;
  642. int32 metric;
  643. {
  644.     cp = put16(cp,fam);
  645.     cp = put16(cp,0);
  646.     cp = put32(cp,target);
  647.     cp = put32(cp,0L);
  648.     cp = put32(cp,0L);
  649.     return put32(cp,metric);
  650. }
  651. /* Route timeout handler. If route has already been marked for deletion
  652.  * then delete it. Otherwise mark for deletion and restart timer.
  653.  */
  654. void
  655. rt_timeout(s)
  656. void *s;
  657. {
  658.     register struct route *rp = (struct route *)s;
  659.  
  660.     stop_timer(&rp->timer);
  661.     if(rp->metric < RIP_INFINITY){
  662.         rp->metric = RIP_INFINITY;
  663. #if 0
  664.         if(dur_timer(&rp->timer) == 0)
  665. #endif
  666.             set_timer(&rp->timer,RIP_TTL*1000L);
  667.         /* wait 2/3 of timeout before garbage collect */
  668.         set_timer(&rp->timer,dur_timer(&rp->timer)*2/3);
  669.         rp->timer.func = rt_timeout;
  670.         rp->timer.arg = (void *)rp;
  671.         start_timer(&rp->timer);
  672.         /* Route changed; mark it for triggered update */
  673.         rp->flags |= RTTRIG;
  674.         rip_trigger();
  675.     } else {
  676.         rt_drop(rp->target,rp->bits);
  677.     }
  678. }
  679.